#include "path.hpp"

#include "qbe/src/ecs/app.hpp"

#include "qbe/src/ecs/query.hpp"

#include "qbe/src/axis/axis.hpp"
#include "qbe/src/input/input.hpp"
#include "qbe/src/select/select.hpp"
#include "qbe/src/state/state.hpp"
#include "qbe/src/undoRedo/undoRedo.hpp"
#include "qbe/src/utils/utils.hpp"

#include "qbe/src/layout/layout.hpp"

#include "qlib/all.h"

#include "../components.hpp"
#include "../events.hpp"

#include "qbe/src/ui_message/message.h"

#include <QMessageBox>

#include "../../operationLayer/operationLayer.h"

namespace qbe::draw::path {

// 移除标记
void clear_tag(ecs::Query query) {
  auto& param = query.get_resource<Models>();

  // 遍历Tag并移除
  if (param.clear_tag) {
    auto& cell = query.get_resource<qlib::Cell::s_ptr>();
    auto& reg = cell->reg;

    auto view_cache_add = reg.view<PathCacheAddTag>();
    view_cache_add.each([&reg](entt::entity e) { reg.remove<PathCacheAddTag>(e); });

    auto view_cache_update = reg.view<PathCacheUpdateTag>();
    view_cache_update.each([&reg](entt::entity e) { reg.remove<PathCacheUpdateTag>(e); });

    auto view_cache_delete = reg.view<PathCacheDeleteTag>();
    view_cache_delete.each([&reg](entt::entity e) { reg.remove<PathCacheDeleteTag>(e); });

    auto view_add = reg.view<PathAddTag>();
    view_add.each([&reg](entt::entity e) { reg.remove<PathAddTag>(e); });

    param.clear_tag = false;
  }
}

// 添加临时对象
void add_cache_obj(entt::registry& reg, ecs::EventWriter<draw::Event> event_writer, layout::LayoutCmd& cmd, entt::entity entity, Models& model,
                   ecs::Query query) {
  auto path = reg.get<qlib::Path::s_ptr>(entity);

  if (path->elements.size() == 0) {
    model.line = render::LineMesh(path->spine.points);
  } else {
    qlib::PolygonPtrArray poly_arr;
    path->to_polygons(false, qlib::Tag(0, 0), poly_arr);

    model.width_line.meshs.clear();
    for (auto poly : poly_arr) {
      model.width_line.meshs.push_back({poly->points, true});
    }
  }

  if (model.complete_entity != entt::null) {
    reg.remove<select::SelectTag>(model.complete_entity);
    auto& sele_event_writer = query.get_event_writer<select::Event>();
    sele_event_writer.send({select::Code::SelectUpdate});
    sele_event_writer.send({select::Code::HoverUpdate});

    model.complete_entity = entt::null;
  }

  auto& ol = query.get_resource<ol::Models>();
  ol.clearAllSelect();

  event_writer.send({Code::PathCacheAdd});
}

// 更新临时对象
void update_cache_obj(entt::registry& reg, ecs::EventWriter<draw::Event> event_writer, layout::LayoutCmd& cmd, entt::entity entity, Models& model) {
  auto path = reg.get<qlib::Path::s_ptr>(entity);

  if (path->elements.size() == 0) {
    model.line = render::LineMesh(path->spine.points);
  } else {
    model.line = render::LineMesh(path->spine.points);

    qlib::PolygonPtrArray poly_arr;
    path->to_polygons(false, qlib::Tag(0, 0), poly_arr);

    model.width_line.meshs.clear();
    for (auto poly : poly_arr) {
      model.width_line.meshs.push_back({poly->points, true});
    }
  }

  event_writer.send({Code::PathCacheUpdate});
}

// 删除临时对象
void delete_cache_obj(entt::registry& reg, ecs::EventWriter<draw::Event> event_writer, layout::LayoutCmd& cmd, entt::entity entity, Models& model) {
  reg.destroy(entity);

  event_writer.send({Code::PathCacheDelete});
}

// 添加对象
void add_obj(entt::registry& reg, ecs::EventWriter<draw::Event> event_writer, layout::LayoutCmd& cmd, entt::entity entity,
             undoRedoT::UndoRedoModule& undoRedoModuel, qlib::Cell::s_ptr cell, Models& model, ecs::Query query, state::State& state) {
  auto path = reg.get<qlib::Path::s_ptr>(entity);
  bool have_layer = state.getCurrentLayer(path->layer);

  if (have_layer) {
    // if (!path->have_width) {
    //   auto& ele = path->elements.emplace_back();
    //   auto& ho = ele.half_width_and_offset.emplace_back();

    //   ele.bend_type = qlib::BendType::Circular;
    //   ele.join_type = qlib::JoinType::Round;
    // }

    auto e = cmd.add(path);
    model.complete_entity = e;

    undoRedoModuel.start(cell);
    undoRedoModuel.add(e);
    undoRedoModuel.end();

    model.clear_tag = true;
    reg.emplace<PathAddTag>(e);
    event_writer.send({Code::PathAdd});

    reg.emplace_or_replace<select::SelectTag>(e);
    auto& sele_event_writer = query.get_event_writer<select::Event>();
    sele_event_writer.send({select::Code::SelectUpdate});
    sele_event_writer.send({select::Code::HoverUpdate});
  }

  delete_cache_obj(reg, event_writer, cmd, entity, model);
}

// 退出绘制模式时回调
void exit_callback(ecs::Query query, state::AllModeType new_mode) {
  // 获取参数
  auto& param = query.get_resource<Models>();

  if (param.complete_entity != entt::null && !state::isModeType<state::EditingModeType>(new_mode)) {
    auto& cell = query.get_resource<qlib::Cell::s_ptr>();
    auto& reg = cell->reg;

    reg.remove<select::SelectTag>(param.complete_entity);
    auto& sele_event_writer = query.get_event_writer<select::Event>();
    sele_event_writer.send({select::Code::SelectUpdate});
    sele_event_writer.send({select::Code::HoverUpdate});

    param.complete_entity = entt::null;
  }

  // 如果正在绘制
  if (param.state != State::None && param.entity != entt::null) {
    // 获取cell和reg
    auto& cell = query.get_resource<qlib::Cell::s_ptr>();
    auto& reg = cell->reg;
    auto& cmd = query.get_resource<layout::LayoutCmd>();
    auto& models = query.get_resource<Models>();

    // 获取事件写入器
    auto event_writer = query.get_event_writer<draw::Event>();

    // 外部通知删除
    delete_cache_obj(reg, event_writer, cmd, param.entity, models);

    // 重置参数
    param.state = State::None;
    param.entity = entt::null;

    auto& absorbModule = query.get_resource<qbe::adsorb::AdsorbModel>();
    absorbModule.close_diagonal_start();
  } else {
    // 重置参数
    param.state = State::None;
    param.entity = entt::null;

    auto& absorbModule = query.get_resource<qbe::adsorb::AdsorbModel>();
    absorbModule.close_diagonal_start();
  }
}

// 退出绘制模式时回调
void exit(ecs::Query query) {
  // 获取参数
  auto& param = query.get_resource<Models>();

  if (param.complete_entity != entt::null) {
    auto& cell = query.get_resource<qlib::Cell::s_ptr>();
    auto& reg = cell->reg;

    reg.remove<select::SelectTag>(param.complete_entity);
    auto& sele_event_writer = query.get_event_writer<select::Event>();
    sele_event_writer.send({select::Code::SelectUpdate});
    sele_event_writer.send({select::Code::HoverUpdate});

    param.complete_entity = entt::null;
  }

  // 如果正在绘制
  if (param.state != State::None && param.entity != entt::null) {
    // 获取cell和reg
    auto& cell = query.get_resource<qlib::Cell::s_ptr>();
    auto& reg = cell->reg;
    auto& cmd = query.get_resource<layout::LayoutCmd>();
    auto& models = query.get_resource<Models>();

    // 获取事件写入器
    auto event_writer = query.get_event_writer<draw::Event>();

    // 外部通知删除
    delete_cache_obj(reg, event_writer, cmd, param.entity, models);

    // 重置参数
    param.state = State::None;
    param.entity = entt::null;

    auto& absorbModule = query.get_resource<qbe::adsorb::AdsorbModel>();
    absorbModule.close_diagonal_start();
  } else {
    // 重置参数
    param.state = State::None;
    param.entity = entt::null;

    auto& absorbModule = query.get_resource<qbe::adsorb::AdsorbModel>();
    absorbModule.close_diagonal_start();

    // 退出模式
    auto& state = query.get_resource<state::State>();
    state.exit();
  }
}

// 初始化
void init(ecs::Commands command, ecs::Query query) {
  // 添加到资源
  Models param;
  command.insert_resource(param);

  // 添加模式退出回调
  auto& state = query.get_resource<state::State>();
  state.addExitCall(state::DrawingModeType::Path, exit_callback);

  auto& cell = query.get_resource<qlib::Cell::s_ptr>();
  auto& reg = cell->reg;

  // 线宽度恢复
  auto view = reg.view<qlib::Path::s_ptr>();
  for (auto [e, path] : view.each()) {
    path->update();
  }
}

// 帧开始，模式转换
void stateTransformBegin(Models& param, state::State& state, input::HandleBundle* handle, ecs::Bus& bus) {
  // 执行操作的状态完成则回退，不存在维持情况
  assert(param.state == State::None || param.state == State::Begin || param.state == State::Wait);
  // assert(param.state != State::Create);
  // assert(param.state != State::Upatde);
  // assert(param.state != State::Complete);

  // 快捷键
  input::KeyBoardShortcuts kbs;
  kbs.keyBase = vsg::KEY_q;
  kbs.keyModifier = vsg::MODKEY_Shift;

  // 如果不处于等待模式，则按下必然弹窗
  if (param.state != State::Wait && handle->keyReleased(kbs)) {
    // 按下则发送事件
    bus.send(qbe::UiMessage::CreatePathUiOpen());

    // 等待ui消息
    param.state = State::Wait;
    return;
  }

  // 等待模式
  if (param.state == State::Wait) {
    // 尝试接收消息
    auto ok_mes = bus.receive<qbe::UiMessage::CreatePathUiOk>();
    auto cancel_mes = bus.receive<qbe::UiMessage::CreatePathUiCancel>();

    // 当确认时ok时
    if (!ok_mes.empty()) {
      // 获取参数
      param.line_width = ok_mes.back().line_width;
      param.cente_line_width = ok_mes.back().cente_line_width;
      param.radius_turning = ok_mes.back().radius_turning;
      param.use_ui = true;

      // 已有线，则更新
      if (param.entity != entt::null) {
        param.state = State::Upatde;
      } else {
        // 无线则等待开始
        param.state = State::Begin;
      }

      return;
    }

    // 当取消时
    if (!cancel_mes.empty()) {
      param.use_ui = false;
      param.is_esc = cancel_mes.back().is_esc;

      // 已有线，则开始
      if (param.entity != entt::null) {
        param.state = State::Begin;
      } else {
        // 无线则等待开始
        param.state = State::None;
      }
      return;
    }
  }

  // 如果不处于弹窗，按esc则取消
  if (param.state != State::Wait && handle->keyReleased(vsg::KEY_Escape)) {
    if (param.is_esc) {
      param.is_esc = false;
    } else {
      param.state = State::Cancel;
      return;
    }
  }

  // 如果按下左键，则创建
  if (handle->mousePressed(vsg::ButtonMask::BUTTON_MASK_1)) {
    param.state = State::Create;
    if (param.line_width != 0.0) {
      param.use_ui = true;
    }
    return;
  }

  // 右键按下则完成
  if (param.state == State::Begin && handle->mousePressed(vsg::ButtonMask::BUTTON_MASK_3)) {
    param.state = State::Complete;
    return;
  }

  // 回车按下则完成
  if (param.state == State::Begin && handle->keyReleased(vsg::KEY_Return)) {
    param.state = State::Complete;
    return;
  }

  // 鼠标移动且有对象，则更新
  if (param.state == State::Begin && param.entity != entt::null && handle->mouse_move) {
    param.state = State::Upatde;
    return;
  }
}

// 帧尾-退出模式
void stateTransformEnd(State& state) {
  // 操作模式执行完就回退
  if (state == State::Create || state == State::Upatde || state == State::Complete || state == State::Cancel) {
    state = State::Begin;
  }
}

// 获取鼠标当前点，需要考虑：吸附、斜角吸附
qlib::Vec2d getNowPoint(ecs::Query query, qlib::Vec2d prePoint) {
  {
    auto& axisModule = query.get_resource<axis::Axis>();
    qlib::Vec2d pos = {axisModule.real_x, axisModule.real_y};

    auto& absorbModule = query.get_resource<qbe::adsorb::AdsorbModel>();
    absorbModule.set_diagonal_start(prePoint);

    return pos;
  }

  auto& state = query.get_resource<state::State>();

  if (!state.isAdsorption()) {
    if (!state.isAngleTheAdsorption()) {
      auto& axisModule = query.get_resource<axis::Axis>();
      qlib::Vec2d pos = {axisModule.real_x, axisModule.real_y};
      return pos;
    } else {
      auto& axisModule = query.get_resource<axis::Axis>();
      qlib::Vec2d pos = {axisModule.real_x, axisModule.real_y};
      return utils::getAngleAdsorbedPoint(prePoint, pos);
    }
  } else {
    if (!state.isAngleTheAdsorption()) {
      return utils::getAdsorbedPoint(query);
    } else {
      qlib::Vec2d pos = utils::getAdsorbedPoint(query);
      return utils::getAngleAdsorbedPoint(prePoint, pos);
    }
  }
}

void updateLine(qlib::Path::s_ptr path, double width, double radius) {
  path->elements.resize(1);
  path->elements[0].bend_radius = radius;
  path->elements[0].bend_type = qlib::BendType::Circular;
  path->elements[0].half_width_and_offset.resize(path->spine.points.size());

  for (size_t i = 0; i < path->spine.points.size(); i++) {
    path->elements[0].half_width_and_offset[i] = qlib::Vec2d(width / 2.0, 0);
  }
}

void update(ecs::Query query, ecs::Bus& bus) {
  // 判断编辑模式为绘制
  auto& state = query.get_resource<state::State>();

  if (state.getDrawingMode() != state::DrawingModeType::Path)
    return;

  auto& select_models = query.get_resource<select::OverallModel>();
  // select_models.mouse_press = false;
  // select_models.mouse_release = false;

  {
    auto& ol = query.get_resource<ol::Models>();

    uint32_t currentLayer = 0;
    if (state.getCurrentLayer(currentLayer)) {
      bool currentLayerHide = ol.currentLayerIsHide(currentLayer);
      if (currentLayerHide) {
        exit(query);
        return;
      }
    }
  }

  // 获取cell和reg
  auto& cell = query.get_resource<qlib::Cell::s_ptr>();
  auto& reg = cell->reg;

  auto& layout_cmd = query.get_resource<layout::LayoutCmd>();

  // 获取输入 坐标系 撤销恢复
  auto& handModule = query.get_resource<vsg::ref_ptr<input::HandleBundle>>();
  auto& axisModule = query.get_resource<axis::Axis>();
  auto& undoRedoModule = query.get_resource<undoRedoT::UndoRedoModule>();

  // 获取参数
  auto& param = query.get_resource<Models>();
  auto& entity = param.entity;

  // 获取事件写入器
  auto event_writer = query.get_event_writer<draw::Event>();

  stateTransformBegin(param, state, handModule, bus);

  {
    uint32_t layer;
    if (!state.getCurrentLayer(layer)) {
      QMessageBox::information(nullptr, QObject::tr("error"), QObject::tr("No layer selected, unable to draw"));
      exit(query);
    }
  }

  // 获取当前鼠标点
  layout::Vec2d pos = {axisModule.real_x, axisModule.real_y};

  // 创建流程
  if (param.state == State::Create) {
    // 对象为空则新建
    if (entity == entt::null) {
      // 新建实体和指针
      entity = reg.create();
      auto path_ptr = qlib::Path::create();

      // 绑定指针到实体
      reg.emplace<qlib::Path::s_ptr>(entity, path_ptr);

      // 获取点集
      auto& points = path_ptr->spine.points;

      // 添加两个点
      points.emplace_back(pos);
      points.emplace_back(pos + 0.001);

      // 根据面板参数，设置有宽度的线
      if (param.use_ui) {
        path_ptr->width = param.line_width;
        path_ptr->center_width = param.cente_line_width;
        path_ptr->radius = param.radius_turning;
        path_ptr->update();
      }
      path_ptr->update();

      // 通知外部更新
      add_cache_obj(reg, event_writer, layout_cmd, entity, param, query);
      param.clear_tag = true;
    } else {
      // 对象不为空则获取
      if (param.is_moveing) {
        auto& path_ptr = reg.get<qlib::Path::s_ptr>(entity);
        auto& points = path_ptr->spine.points;

        pos = getNowPoint(query, points[points.size() - 2]);

        // 修改最后一个点，再加一个点
        points.back() = pos;
        points.emplace_back(pos + (points.back() - points[points.size() - 2]).normalize() * 0.001);

        if (path_ptr->elements.size() != 0) {
          path_ptr->width = param.line_width;
          path_ptr->center_width = param.cente_line_width;
          path_ptr->radius = param.radius_turning;
          path_ptr->update();
        }
        path_ptr->update();

        // 通知外部更新
        update_cache_obj(reg, event_writer, layout_cmd, entity, param);
        param.clear_tag = true;
        param.is_moveing = false;
        param.use_ui = false;
      }
    }
  }

  // 更新逻辑
  if (param.state == State::Upatde) {
    // 获取点集
    auto& path_ptr = reg.get<qlib::Path::s_ptr>(entity);
    auto& points = path_ptr->spine.points;

    pos = getNowPoint(query, points[points.size() - 2]);

    if (param.use_ui) {
      path_ptr->width = param.line_width;
      path_ptr->center_width = param.cente_line_width;
      path_ptr->radius = param.radius_turning;
      path_ptr->update();
    }

    // 修改最后一个点
    points.back() = pos;
    path_ptr->update();

    // 通知外部更新
    update_cache_obj(reg, event_writer, layout_cmd, entity, param);
    param.clear_tag = true;
    param.is_moveing = true;
  }

  if (param.state == State::Cancel)
    exit(query);

  // 完成逻辑
  if (param.state == State::Complete) {
    // 获取点集，退出最后一个
    auto& path_ptr = reg.get<qlib::Path::s_ptr>(entity);
    auto& points = path_ptr->spine.points;
    points.pop_back();

    // 满足要求
    if (points.size() >= 2) {
      // 通知外部
      add_obj(reg, event_writer, layout_cmd, entity, undoRedoModule, cell, param, query, state);
      param.clear_tag = true;
    } else {
      // 不满足则移除
      delete_cache_obj(reg, event_writer, layout_cmd, entity, param);
      param.clear_tag = true;
    }

    // 重置参数
    param.state = State::None;
    param.entity = entt::null;

    auto& absorbModule = query.get_resource<qbe::adsorb::AdsorbModel>();
    absorbModule.close_diagonal_start();
  }

  stateTransformEnd(param.state);
}

void Plugin::build(ecs::App& app) {
  app.add_stage<InitStage>();
  app.add_stage<UpdateStage>();

  app.init_event<Event>();

  app.add_systems<InitStage>(init);
  app.add_systems<UpdateStage>(update);
  app.add_systems<ecs::stage::Last>(clear_tag);
}

}  // namespace qbe::draw::path
